package com.ilink.groundservice.service.impl.AiX;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ilink.groundservice.entity.PO.AiX.AiXCourse;
import com.ilink.groundservice.entity.PO.AiX.AiXTag;
import com.ilink.groundservice.entity.PO.AiX.AiXTagConnect;
import com.ilink.groundservice.entity.VO.AiX.AiXCourseResponse;
import com.ilink.groundservice.mapper.AiX.AiXCourseMapper;
import com.ilink.groundservice.mapper.AiX.AiXTagConnectMapper;
import com.ilink.groundservice.mapper.AiX.AiXTagMapper;
import com.ilink.groundservice.service.AiX.AiXCourseService;
import com.ilink.ilinkapi.dto.ground.AiX.AiXAreaFilterRequest;
import com.ilink.ilinkapi.dto.ground.AiX.Course.AiXCourseInsertRequest;
import com.ilink.ilinkapi.dto.ground.AiX.Course.AiXCourseUpdateRequest;
import com.ilink.ilinkcommon.domain.R;
import com.ilink.ilinkcommon.service.oss.MinioService;
import com.ilink.ilinkcommon.utils.SnowflakeIdGenerator;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor
public class AiXCourseServiceImpl implements AiXCourseService {

  private final AiXCourseMapper aiXCourseMapper;
  private final AiXTagMapper aiXTagMapper;
  private final AiXTagConnectMapper aiXTagConnectMapper;
  private final MinioService minioService;

  @Override
  public IPage<AiXCourseResponse> getCourses(AiXAreaFilterRequest request) {
    Page<AiXCourse> page = new Page<>(request.getPage(), request.getSize());

    LambdaQueryWrapper<AiXCourse> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(request.getAreaId() != null, AiXCourse::getAreaId, request.getAreaId());

    if (request.getTag() != null && !request.getTag().isEmpty()) {
      AiXTag tag = aiXTagMapper.selectOne(new LambdaQueryWrapper<AiXTag>().eq(AiXTag::getTagName, request.getTag()).last("LIMIT 1"));
            if (tag != null) {
        List<Long> courseIds = aiXTagConnectMapper.selectList(
            new LambdaQueryWrapper<AiXTagConnect>()
                .eq(AiXTagConnect::getTagId, tag.getTagId())
                .eq(AiXTagConnect::getConnectTable, "ai_x_area_course")
        ).stream().map(AiXTagConnect::getConnectTableKey).collect(Collectors.toList());

        if (!courseIds.isEmpty()) {
          queryWrapper.in(AiXCourse::getCourseId, courseIds);
        } else {
          return new Page<>(request.getPage(), request.getSize());
        }
      }
    }

    if (!request.getKeyword().isEmpty()) {
      queryWrapper.and(wrapper ->
          wrapper.like(AiXCourse::getCourseTitle, request.getKeyword())
              .or().like(AiXCourse::getIntroduction, request.getKeyword())
      );
    }

    IPage<AiXCourse> coursePage = aiXCourseMapper.selectPage(page, queryWrapper);

    List<AiXCourseResponse> responseList = coursePage.getRecords().stream().map(course -> {
      AiXCourseResponse response = new AiXCourseResponse();
      response.setCourseId(course.getCourseId());
      response.setCourseTitle(course.getCourseTitle());
      response.setIntroduction(course.getIntroduction());
      response.setAuthors(course.getAuthors());
      response.setAreaId(course.getAreaId());
      response.setTargetUrl(course.getTargetUrl());

      String imagePath = minioService.getBucketFileUrl("dataset-square-migrate", course.getCoverUrl());
      response.setCoverUrl(imagePath != null ? imagePath : "");

      List<String> tags = aiXTagConnectMapper.selectList(
          new LambdaQueryWrapper<AiXTagConnect>()
              .eq(AiXTagConnect::getConnectTableKey, course.getCourseId())
              .eq(AiXTagConnect::getConnectTable, "ai_x_area_course")
      ).stream().map(tagConnect -> {
        AiXTag tag = aiXTagMapper.selectById(tagConnect.getTagId());
        return tag != null ? tag.getTagName() : null;
      }).filter(tagName -> tagName != null).collect(Collectors.toList());
      response.setTags(tags);

      return response;
    }).collect(Collectors.toList());

    Page<AiXCourseResponse> responsePage = new Page<>(coursePage.getCurrent(), coursePage.getSize(), coursePage.getTotal());
    responsePage.setRecords(responseList);

    return responsePage;
  }

  @Override
  @Transactional
  public R insertCourse(AiXCourseInsertRequest request) {
    SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1, 1);
    Long courseId = idGenerator.nextId();

    AiXCourse course = new AiXCourse();
    course.setCourseId(courseId);
    course.setCourseTitle(request.getCourseTitle());
    course.setIntroduction(request.getIntroduction());
    course.setAuthors(request.getAuthors());
    course.setAreaId(request.getAreaId());
    course.setTargetUrl(request.getTargetUrl());

    String objectName = "area/" + request.getAreaId() + "/course/" + courseId + getFileExtension(request.getCoverImage().getOriginalFilename());
    boolean isUploaded = minioService.uploadBucketFile(request.getCoverImage(), "dataset-square-migrate", objectName);
    if (!isUploaded) {
      return R.error("课程封面上传失败");
    }
    course.setCoverUrl(objectName);

    aiXCourseMapper.insert(course);

    if (request.getTags() != null) {
      handleTags(request.getTags(), courseId);
    }

    return R.ok("课程插入成功");
  }

  @Override
  @Transactional
  public R updateCourse(AiXCourseUpdateRequest request) {
    Long courseId = request.getCourseId();

    AiXCourse course = new AiXCourse();
    course.setCourseId(courseId);
    course.setCourseTitle(request.getCourseTitle());
    course.setIntroduction(request.getIntroduction());
    course.setAuthors(request.getAuthors());
    course.setAreaId(request.getAreaId());
    course.setTargetUrl(request.getTargetUrl());

    aiXCourseMapper.updateById(course);

    aiXTagConnectMapper.delete(new LambdaQueryWrapper<AiXTagConnect>()
        .eq(AiXTagConnect::getConnectTableKey, courseId)
        .eq(AiXTagConnect::getConnectTable, "ai_x_area_course"));

    if (request.getTags() != null) {
      handleTags(request.getTags(), courseId);
    }

    return R.ok("课程更新成功");
  }

  @Override
  @Transactional
  public R updateCourseCover(MultipartFile file, Long courseId, Long areaId) {
    String objectName = "area/" + areaId + "/course/" + courseId + getFileExtension(file.getOriginalFilename());
    boolean isUploaded = minioService.uploadBucketFile(file, "dataset-square-migrate", objectName);
    if (!isUploaded) {
      return R.error("课程封面更新失败");
    }

    AiXCourse course = aiXCourseMapper.selectById(courseId);
    if (course == null) {
      return R.error("课程未找到");
    }

    course.setCoverUrl(objectName);
    aiXCourseMapper.updateById(course);

    return R.ok("课程封面更新成功");
  }

  @Override
  @Transactional
  public void deleteCourse(Long courseId) {
    AiXCourse course = aiXCourseMapper.selectById(courseId);
    if (course != null) {
      String coverUrl = course.getCoverUrl();
      int lastSlashIndex = coverUrl.lastIndexOf('/');
      String directory = coverUrl.substring(0, lastSlashIndex + 1);
      String fileName = coverUrl.substring(lastSlashIndex + 1);
      minioService.deleteBucketFile("dataset-square-migrate", directory, fileName);

      aiXTagConnectMapper.delete(new LambdaQueryWrapper<AiXTagConnect>()
          .eq(AiXTagConnect::getConnectTableKey, courseId)
          .eq(AiXTagConnect::getConnectTable, "ai_x_area_course"));
    }

    aiXCourseMapper.deleteById(courseId);
  }

  @Override
  public AiXCourseResponse getCourse(Long courseId) {
    AiXCourse course = aiXCourseMapper.selectById(courseId);

    AiXCourseResponse response = new AiXCourseResponse();
    response.setCourseId(course.getCourseId());
    response.setCourseTitle(course.getCourseTitle());
    response.setIntroduction(course.getIntroduction());
    response.setAuthors(course.getAuthors());
    response.setAreaId(course.getAreaId());
    response.setTargetUrl(course.getTargetUrl());

    String imagePath = minioService.getBucketFileUrl("dataset-square-migrate", course.getCoverUrl());
    response.setCoverUrl(imagePath != null ? imagePath : "");

    List<String> tags = aiXTagConnectMapper.selectList(
        new LambdaQueryWrapper<AiXTagConnect>()
            .eq(AiXTagConnect::getConnectTableKey, course.getCourseId())
            .eq(AiXTagConnect::getConnectTable, "ai_x_area_course")
    ).stream().map(tagConnect -> {
      AiXTag tag = aiXTagMapper.selectById(tagConnect.getTagId());
      return tag != null ? tag.getTagName() : null;
    }).filter(tagName -> tagName != null).collect(Collectors.toList());
    response.setTags(tags);

    return response;
  }

  @Override
  public List<String> getCourseTags(Long areaId) {
    return aiXTagConnectMapper.getCourseTags(areaId, 8);
  }

  private void handleTags(List<String> tags, Long courseId) {
    SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1, 1);
    for (String tag : tags) {
      AiXTag existingTag = aiXTagMapper.selectOne(new LambdaQueryWrapper<AiXTag>().eq(AiXTag::getTagName, tag));
      Long tagId;
      if (existingTag == null) {
        tagId = idGenerator.nextId();
        AiXTag newTag = new AiXTag();
        newTag.setTagId(tagId);
        newTag.setTagName(tag);
        aiXTagMapper.insert(newTag);
      } else {
        tagId = existingTag.getTagId();
      }

      AiXTagConnect tagConnect = new AiXTagConnect();
      tagConnect.setConnectId(idGenerator.nextId());
      tagConnect.setConnectTable("ai_x_area_course");
      tagConnect.setConnectTableKey(courseId);
      tagConnect.setTagId(tagId);
      aiXTagConnectMapper.insert(tagConnect);
    }
  }

  private String getFileExtension(String fileName) {
    if (fileName == null) {
      return "";
    }
    int dotIndex = fileName.lastIndexOf('.');
    return dotIndex == -1 ? "" : fileName.substring(dotIndex);
  }
}
